home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / addpcx.zip / DOC.TXT < prev    next >
Text File  |  1988-04-18  |  26KB  |  547 lines

  1. @CHAPTER TITLE = Working with PCX Files
  2.  
  3. @FIRSTPAR = The Picture file format used by ZSoft for their PC Paintbrush 
  4. paint program has become one of the more popular formats around. I 
  5. personally took an interest in it originally because I needed to get 
  6. diagrams into Ventura Publisher; which not only accepts .pcx files, 
  7. but will also expand and contract them sensibly.
  8.  
  9. The format turned out to be easy to work with.  The files can be loaded 
  10. and written quickly, using a set of simple functions.  Screen update 
  11. is fast, and the screen can easily be panned around a large picture. 
  12. Drawing operations for multi-color formats aren't as fast, but that's 
  13. due to the data structure that I've chosen. 
  14.  
  15. I'd like to start by describing PCX pictures in general terms.  The 
  16. Header and Color palette are complicated enough to deserve some more 
  17. detail.  I'll finish with a description of the modules that I've written 
  18. to generate, write, read and display PCX pictures.  You'll probably 
  19. want to make many improvements to them, but I'm confidant that they'll 
  20. get a PCX related project off the ground for you. 
  21.  
  22. @MAJOR HEADING = The Basic Structure
  23.  
  24. A PCX file consists of a 128 byte header, followed by one or more 
  25. compressed picture planes.  In memory, each plane is basically a bit 
  26. map, with each bit usually corresponding to a pixel on the screen.  The 
  27. number of bits per pixel, pixels per byte, bytes per line, lines per 
  28. plane and planes per picture are all stored in the header.
  29.  
  30. On the EGA board, there are four planes (see figure 1.) Bit (X,Y) 
  31. in each plane corresponds to pixel (X,Y) on the screen.  The binary 
  32. value of the four (X,Y) bits in each plane is used to index into the 
  33. color palette. On the CGA & HERC boards, only 1 plane is used.  For 
  34. the 720x348 HERC and 640x200 CGA modes, each bit in the plane corresponds 
  35. to a single pixel on the screen.  Using the 320x200 by 4 color CGA 
  36. mode, there is again only one plane, but each pixel is made up of 
  37. two adjacent bits.
  38.  
  39. It's possible to make a 1000x1000 by 2 color drawing which can be 
  40. displayed on a CGA board 640x200 dots at a time, then show it on a 
  41. Hercules board 720x348 dots at a time, but a picture isn't always 
  42. so portable. A 320x200 CGA picture has to be translated before it 
  43. can be shown in another mode.
  44.  
  45. As you can imagine, drawing the picture on the screen is easy <197> 
  46. all that's needed is a block move of each line of the picture to the 
  47. VRAM on the board. The trade off is that there has to be some interpretation 
  48. of the header information, and the pictures don't look quite the same 
  49. from one board to another due to changes in dot width and height.
  50.  
  51. @MAJOR HEADING = The Header
  52.  
  53. The structure for the header looks like this:
  54.  
  55. @LISTING = typedef struct {<R>
  56.    unsigned char red, green, blue;<R>
  57. } TRIPLET;<R>
  58. <R>
  59. typedef struct {<R>
  60.    char maker,<R>
  61.      version,<R>
  62.     code,<R>
  63.     bpp;<R>
  64.    int    x1, y1, x2, y2,<R>
  65.        hres, vres;<R>
  66.    TRIPLET triple[16];<R>
  67.    char vmode, <R>
  68.        nplanes;<R>
  69.    int    bpl;<R>
  70.    char __unused[128-68];<R>
  71. } PCXHDR;
  72.  
  73. The fields<B> maker<D>, <B>version<D>, <B>code<D> and <B>vmode<D> 
  74. all currently have fixed values <197> 10, 5, 1, & 0. They represent 
  75. the code for the program that generated the picture, its version number 
  76. and the type of compression that was applied to the picture planes; 
  77. <B>vmode<D> is currently ignored; and <B>__unused<D> is reserved for 
  78. future expansion.
  79.  
  80. <B>hres <D>and <B>vres<D> represent the number of dots, horizontal 
  81. and vertical, on the video board to be used.  <B>nplanes <D>is the 
  82. number of picture planes used,<B> bpp<D> is the number of bits per 
  83. pixel and <B>bpl<D> is the number of bytes that are used to store 
  84. a horizontal line of the picture. (<B>x1,y1<D>)-(<B>x2,y2<D>) refer 
  85. to the upper left and lower right corners of the picture.  For a standard 
  86. 640x350x16 EGA picture, we would get the following: <B>hres<D>=640, 
  87. <B>vres<D>=350, <B>x1<D>=0, <B>y1<D>=0, <B>x2<D>=639, <B>y2<D>=349, 
  88. <B>nplanes<D>=4, <B>bpp<D>=1 and <B>bpl<D>=80. 
  89.  
  90. It's interesting to note that PC PaintBrush seems to take these numbers 
  91. very seriously.  If a picture is made after PaintBrush is set up to 
  92. use a HERC board, it won't even be recognized as a picture file if 
  93. PaintBrush is then set up to use an EGA board. That's a bit picky 
  94. considering that a HERC picture is black and white, and an EGA board 
  95. supports those colors.
  96.  
  97. So, if you plan to use the pictures that you generate on some existing 
  98. program, be careful to model your picture after one of the various 
  99. video board modes.  To make a picture with a different size, only 
  100. (<B>x2, y2<D>) and <B>bpl<D> would have to change; and the easiest 
  101. way to add colors would be to add planes.  Although the software that 
  102. I've written only supports a few of the standard configurations, it'll 
  103. probably be easy to modify.
  104.  
  105. @MAJOR HEADING = The Color Palette
  106.  
  107. The palette information is stored in the array of 16 triples.  It's 
  108. the only part of the PCX format that's really tricky <197> being totally 
  109. board dependent. Perhaps Shannon at ZSoft can send Dave a letter explaining 
  110. it better.  Here's the way I understand it:
  111.  
  112. The IBM EGA adapter has 16 single byte color registers, each of which 
  113. holds a two bit intensity value of from 0 to 3 for each color gun 
  114. (Red, Green, and Blue.) The intensity values are stored as pairs of 
  115. bits, like this: "xxRGBrgb".  The first two bits, 7 & 6, are ignored.  The 
  116. next three bits are the high bits of the intensity values for the 
  117. Red, Green & Blue guns.  The last three bits are the low bits of the 
  118. same intensity values. This allows each of the 16 registers to contain 
  119. one of 64 possible color combinations.
  120.  
  121. The PCX header has a 16 element palette table, one element per color 
  122. register.  Each element is a three byte structure (TRIPLET) which 
  123. holds an intensity value for each color gun.  To set the color for 
  124. any given palette register, the Red, Green & Blue intensity bytes 
  125. are set with the desired intensity for that color multiplied by 85.  (I 
  126. have no idea why we multiply by 85.) To set the EGA palette register, 
  127. we take the intensity value, divide by 85, twiddle the bits, then 
  128. take the easy route to the palette register by calling the BIOS Set 
  129. Palette function.
  130.  
  131. The CGA board has a Color Select Register at I/O location 0x3d9.  The 
  132. bit configuration for this register is "xxCAIRGB".  The first two 
  133. bits are ignored.  The C bit selects one of two pre-defined palettes, 
  134. called Color Sets by IBM.  Set 1 is Background, Green, Red & Brown.  Set 
  135. 2 is Background, Cyan, Magenta & White.  The Background color is one 
  136. of 16 colors formed using the IRGB bits.  I is an intensity bit, R, 
  137. G & B are enables for the Red, Green and Blue color guns, respectively.  If 
  138. the A bit is set, it "Selects (an) Alternate, Intensified set of colors 
  139. in Grapics Mode" (see ref. 1.) To me, this translates into 4 color 
  140. sets and one of 16 background colors.
  141.  
  142. Storage of the CGA palette settings in the PCX header is simple: The 
  143. first byte of the first element in the palette table contains a background 
  144. color, multiplied by 16.  The first byte of the second element in 
  145. the palette table apparently contains a three bit value, multiplied 
  146. by 32.  (I haven't been able to figure out what to do with the third 
  147. bit.) At any rate, there are 8 such settings in the PCX headers palette 
  148. table, but it seems to me that only one of them can be in effect at 
  149. a time.
  150.  
  151. There are probably many more palette formats for other boards, but 
  152. I don't know of any documentation for them.  In the code that accompanies 
  153. this article, the pcx_set_palette() function has a load_palette flag 
  154. which must be set in order to get the routine to tinker with the palette 
  155. registers.  I didn't bother much with the palette for a number of 
  156. reasons; the first one being that the palette is automatically set 
  157. each time a graphics mode is selected; another being that Ventura 
  158. Publisher ignores it. 
  159.  
  160. @MAJOR HEADING = Compressing a Plane
  161.  
  162. When in a file, each plane in the picture is compressed.  The compression 
  163. is very simple; designed simply to take advantage of the fact that 
  164. a byte value will often repeat. 
  165.  
  166. The read byte algorithm works like this: Read a byte.  If the two 
  167. high order bits are not set ((byte & 0xc0) != 0xc0), then return the 
  168. byte. If the two high order bits are set ((byte & 0xc0) == 0xc0), 
  169. then the remaining bits represent a repeat count (count = byte & 0x3f) 
  170. and the next byte is the value that repeats.  As such, the repeat 
  171. count can never be greater than 0x3f, or 63.  The write byte algorithm 
  172. is obviously the opposite operation.
  173.  
  174. @MAJOR HEADING = The Software
  175.  
  176. Originally, what I wanted to do was copy schematics into Ventura.  I 
  177. sat in front of the system for many sleepless nights decoding DXF 
  178. files, only to find in the end that the GEM files Ventura creates 
  179. from the DXF files don't properly scale text.  
  180.  
  181. To make a long story short, I wrote most of a DXF to PCX converter, 
  182. then (balking at the prospect of having to write a font editor, create 
  183. fonts, and write the code to scale them,) scrapped the idea <197> 
  184. it was less time consuming to just chop the schematics into small 
  185. blocks. In the mean time, I'd written a (simple) board independent 
  186. graphics package, several test routines, and a slide show program.  As 
  187. you've just guessed, text is not implemented.
  188.  
  189. Everything was compiled using Manx Aztec 'C 86, V. 4.10a.  With the 
  190. exception of the code that handles flicker on the CGA board, it should 
  191. compile without complaint on most systems.  Note, however, that it'll 
  192. only work in the large data model; not only because of the huge amount 
  193. of RAM that it uses, but because of the way I accessed the VRAM.
  194.  
  195. There isn't enough space to list all the code, so I'll document the 
  196. software here, and you can download the files from one of the following 
  197. sources: The file "$$$PCX.ARC" will be on the MicroC BBS long before 
  198. you see this; and I'll put it in one of the IBM forums on Compu-Serve, 
  199. in thanks to the many people who put together the EGA.ARC file (see 
  200. ref. 2.) Finally, there'll be a copy in the LISTINGS/IBM.ARC section 
  201. of BIX. 
  202.  
  203. @MAJOR HEADING = The Functions
  204.  
  205. Basically, the functions can be divided into three groups.  The lowest 
  206. level is the board level driver modules.  There's one for the HERC, 
  207. EGA and CGA boards.  To make it easy to use, the PCX module is set 
  208. up as just another video board.  Each module has the same collection 
  209. of functions, each with the same name, although the function name 
  210. is prefixed with the board name to keep them distinct.
  211.  
  212. The next level is what I call the VGR modules, for Video GRaphics.  It's 
  213. a simple interface between the driver modules and the next higher 
  214. level. This level is based on a bunch of macros to allow access to 
  215. the driver level while still being able to switch drivers at run-time.  Using 
  216. these macros, object draw functions can be written which are independent 
  217. of the low level drivers.  So far, I've put in Bressenham's line drawing 
  218. algorithm and an inefficient but functional irregular polygon fill. 
  219. There's a circle drawing algorithm in the May '83 issue of Doctor 
  220. Dobbs Journal which is likely to go in next.
  221.  
  222. The highest level is the Picture level.  The functions at this level 
  223. operate on the following picture structure:
  224.  
  225. @LISTING = typedef struct { <R>
  226.    PCXHDR hdr;<R>
  227.    char **rows[4];<R>
  228. } PCXPIC;
  229.  
  230. (I feel I should warn you that the following few paragraphs are exceptionally 
  231. boring.  If you're not interested in how I chose to handle the pointer 
  232. and bit twiddling details, skip to the next heading...)
  233.  
  234. The PCXHDR is obvious enough, but the rows array deserves some explanation. 
  235. Figure 2 shows how I visualize it when drawing a 640x350x16 EGA-type 
  236. picture.  A plane is a pointer to an array of rows, each of which 
  237. is a pointer to an array of characters.  That array of characters 
  238. contains the bits which constitute a horizontal line of pixels.
  239.  
  240. This approach is relatively inefficient in that it forces several 
  241. 32 bit pointer operations, but it's easy to work with.  As you can 
  242. see, there's currently a hardwired limit of 4 planes, and the arrays 
  243. are dynamically allocated. 
  244.  
  245. For all but the 320x200x4 CGA modes, we can read the bit at position 
  246. (<B>x,y<D>) on a given plane using the following expression:
  247.  
  248. @LISTING = !!(pcx_cpic<197>>>rows[plane][y][x>>>>3] & (0x80 >>>> (x & 7)));
  249.  
  250. The global variable <B>pcx_cpic<D> is defined in the PCX module as 
  251. a pointer to a PCXPIC picture (cpic == current picture) It's used 
  252. to tell the pixel routines what picture to work on.  For the HERC 
  253. board, or the 640x200x2 CGA mode, plane is always zero; the 640x350x16 
  254. EGA mode requires that the operation be repeated once for each plane.  Since 
  255. <B>rows[plane] <D>is a pointer to an array of rows, <B>rows[plane][y] 
  256. <D>is a pointer to the Yth row.  All that's needed now is the byte 
  257. to look at in the row, and the bit in that byte.  The low order three 
  258. bits of <B>x<D> (<B>x<D> & 7) select the bit, and the remaining bits 
  259. of <B>x<D> (<B>x<D> >>>> 3) become the byte offset for the row. The 
  260. above expression would return 1 if the bit at (<B>x,y<D>) is set, 
  261. or zero if it's not.
  262.  
  263. The 320x200x4 CGA mode is slightly more complicated since two adjacent 
  264. bits are used to select a color.  The expression to return the color 
  265. of the pixel at location (<B>x,y<D>) in that mode would be:
  266.  
  267. @LISTING = i = (x & 0x03) <<<< 1;<R>
  268. color = (pcx<197>>>rows[0][y][x>>>>2] & (0xc0 >>>> i)) >>>> (6<197>i);
  269.  
  270. Since each byte represents 4 pixels, <B>x<D>>>>>2 is used as the byte 
  271. offset for the row, and <B>x<D> & 0x03 is the number of the pixel 
  272. in the byte. Multiplying that number by 2 gives <B>i<D>, the number 
  273. of bits from bit 7 that we skip over to get to the first of the two 
  274. bits that select the color of the pixel. 0xc0 >>>> <B>i<D> makes a mask 
  275. for those bits. The big difference between this expression and the 
  276. previous one is that we need a two bit result, so we can't use the 
  277. !! operator to clean up after the bit-wise AND. Shifting to the right 
  278. 6<197><B>i<D> bits does the job.
  279.  
  280. The only difference between the two expressions above and the ones 
  281. actually used in the EGA and CGA modules is that there aren't any 
  282. planes.  The EGA board uses a plane register to enable each plane 
  283. and all four planes use the same memory locations.  The HERC board 
  284. has two pages, which can be thought of as unrelated planes.  I visualized 
  285. each horizontal row of pixels as being an array of columns, so the 
  286. arrays are called columns instead of rows.  The array of pointers 
  287. to each row is dynamically allocated.  The pointers are initialized 
  288. with sequential row addresses for the EGA board, and scattered addresses 
  289. for the HERC and CGA boards. 
  290.  
  291. Although the pointer operations and bit twiddling never get more complicated 
  292. than that, some of the expressions get a bit dense, and aren't much 
  293. fun to read.  Fortunately, all the low level operations are already 
  294. implemented; you can just throw them into your library and use them. 
  295. With that said, let's get down to function names and parameter lists...
  296.  
  297. @MAJOR HEADING = Using the Functions
  298.  
  299. Note that the declarations here don't match the ones in the modules. 
  300. Many functions that don't return anything are declared as returning 
  301. int. Most parameters to most of the functions are not range-checked.
  302.  
  303. @PROTO = void allocf(char *p);<R>
  304. void map_not(int *map,int len);
  305.  
  306. These two come out of my library.  allocf() checks the pointer p to 
  307. see if it's NULL.  If so, it doesn't do anything.  If not, it calls 
  308. free(). If free() returns an error code, an error message is produced, 
  309. and the program quits.  map_not() inverts len ints in the bit-map 
  310. pointed at by map. 
  311.  
  312. @PROTO = void cga_movmem(char far *s,char far *d,int n);<R>
  313. void cga_peekb(char far *p);<R>
  314. void cga_pokeb(char far *p,char b);
  315.  
  316. These functions are the same as movmem(), peekb() and pokeb(); except 
  317. that they wait for a horizontal retrace to start on the CGA board 
  318. before accessing it, to avoid flicker. The cga_movmem() function is 
  319. a straight block move, so you'll have to check for overlapping blocks 
  320. if you plan to move a source to a destination which are both in the 
  321. CGA VRAM.
  322.  
  323. @PROTO = void ega_select_plane(int plane);<R>
  324. int pcx_select_plane(int plane);
  325.  
  326. The EGA VRAM holds 4 planes, each of them mapped into the same memory 
  327. space.  ega_select_plane() is used to enable one or more planes.  If 
  328. it's passed a negative number, the absolute value of that number is 
  329. used as an enable mask, ie: if <B>plane<D> == <197>0x0f, all 4 planes 
  330. are simultaneously enabled.  This is handy when clearing the screen 
  331. since a single setmem() call can clear all four planes! If <B>plane<D> 
  332. is not negative, then it must be from 0 to 3, and only that plane 
  333. is enabled. pcx_select_plane() selects a plane for use by the VGR_ROW() 
  334. macro when drawing on a PCX picture. 
  335.  
  336. @PROTO = void ega_set_palette(char reg,char red,char green,char blue);
  337.  
  338. Sets one of the 16 EGA palette registers.  <B>reg<D> can have a value 
  339. of from 0 to 15.  <B>red, green<D> and <B>blue<D> are the desired 
  340. intensities for each color gun, for that <B>reg<D>ister.  They must 
  341. each have a value of from 0 to 3.
  342.  
  343. @PROTO = int herc_set_page(int page);
  344.  
  345. The HERC driver will default to page 0, but either of the two pages 
  346. can be selected using this function.
  347.  
  348. @PROTO = int *pcx_init(void);<R>
  349. cga_init(void);<R>
  350. ega_init(void);<R>
  351. herc_init(void);<R>
  352. <R>
  353. int    VGR_HRES,<R>
  354.     VGR_VRES,<R>
  355.     VGR_NCOLORS,<R>
  356.     VGR_NBPL; /* #bytes per line */
  357.  
  358. The _init() routines initialize all static local variables in a module, 
  359. allocate any required space (if it hasn't been allocated by a previous 
  360. _init() call,) and set up the VGR module to use the module that was 
  361. INITed.  The VGR module, among other things, holds the four ints shown 
  362. above.  The HERC and EGA modules always set these values, as they're 
  363. constants.  The PCX module will set them only if pcx_cpic is non-null, 
  364. therefore pointing to a valid PCXPIC picture.  The CGA module sets 
  365. them after a VGR_MODE() call.  The _init() functions each return OK 
  366. or ERROR, with ERROR usually meaning that an out of memory condition 
  367. occurred. 
  368.  
  369. @PROTO = int VGR_MODE(int m);
  370.  
  371. Once the VGR module has been set up, using the appropriate *_init() 
  372. function, the "mode" must be set.  Since the _init() call set up the 
  373. array of pointers to functions in the VGR module, it's possible to 
  374. use the #defined macros in vgr.h.  VGR_MODE() is one of those macros. 
  375. <B>m<D> must be one of the following:
  376.  
  377. @LISTING = MODE_TEXT0 <197> text, 80x25<R>
  378. MODE_APA0 <197> APA, 640x350x16<R>
  379. MODE_APA1 <197> APA, 720x348x2<R>
  380. MODE_APA2 <197> APA, 640x200x2<R>
  381. MODE_APA3 <197> APA, 320x200x4
  382.  
  383. When drawing on a PCX picture, the mode is only used to tell the PCX 
  384. module if it's producing a one or two bit per pixel picture; so available 
  385. PCX modes are effectively MODE_APA0 or MODE_APA3.  Available EGA modes 
  386. are MODE_TEXT0 or MODE_APA0; for the CGA it's MODE_TEXT0, MODE_APA2 
  387. or MODE_APA3; and for HERC it's MODE_TEXT0 or MODE_APA1. ERROR or 
  388. OK is returned, with ERROR indicating an invalid mode number. 
  389.  
  390. @PROTO = void VGR_CLEAR()<R>
  391. void VGR_SET(int x,int y,int c)<R>
  392. void VGR_CLR(int x,int y)<R>
  393. void VGR_XOR(int x,int y,int c)<R>
  394. int VGR_GET(int x,int y)<R>
  395. void VGR_ROW(int r,char far *p,int n)<R>
  396. void VGR_MOVE(char far *s,char far *d,int n)<R>
  397. void VGR_PEEKB(char far *p)<R>
  398. void VGR_POKEB(char far *p,int b)
  399.  
  400. These VGR_ macros allow access to the board independent functions. 
  401. _CLEAR clears the screen. _SET sets the color of the pixel at (<B>x,y<D>) 
  402. to <B>c<D>. Note that if <B>c<D> has a value of zero, it has the effect 
  403. of "clearing" the pixel. It's a good idea to not confuse the two operations 
  404. since the HERC module ignores the value of <B>c<D>. _CLR sets the 
  405. color of the pixel to zero. _XOR does a bit-wise exclusive or of the 
  406. color of the pixel with <B>c<D>. Again, the HERC module ignores <B>c<D>. 
  407. _GET returns the color of the pixel. _ROW moves <B>n<D> bytes from 
  408. location <B>p<D> to the VRAM row <B>r<D>. _MOVE, _PEEKB & _POKEB either 
  409. call movmem(), peekb() & pokeb(), or cga_movmem(), cga_peekb() & cga_pokeb(); 
  410. depending on the driver module in use.
  411.  
  412. @PROTO = void vgr_fill(int x,int y,int color);<R>
  413. void vgr_line(int x1,int y1,int x2,int y2,int color);<R>
  414. void vgr_rectangle(int x1,int y1,int x2,int y2,int color);<R>
  415. void vgr_point(int x2,int y2,int color);
  416.  
  417. vgr_line(), _rectangle() and _fill() do what they sound like. vgr_point() 
  418. does one of two things.  If <B>color<D> is -1, the values (<B>x2,y2<D>) 
  419. are copied to the local static values (<B>x1,y1<D>).  If <B>color<D> 
  420. is not -1, vgr_point() calls vgr_line(), then copies (<B>x2,y2<D>) 
  421. to (<B>x1,y1<D>).  This makes it possible to draw lines between a 
  422. series of points. 
  423.  
  424. @PROTO = int vgr_get_board(void);<R>
  425. int vgr_mode(char mode);
  426.  
  427. vgr_get_board() attempts to figure out what kind of video graphics 
  428. board is in use.  The return value is one of TYPE_UNKNOWN, TYPE_EGA, 
  429. TYPE_CGA, TYPE_MDA or TYPE_HERC.  These values are defined in <B>vgr.h<D>. 
  430. vgr_mode() calls the BIOS set graphic mode function; INT 0x10, AH==0. 
  431. See ref. 2, page A-46 for more info on that BIOS call.
  432.  
  433. @PROTO = PCXPIC *pcx_init_pic(int hres,int vres,int nplanes);<R>
  434. void pcx_free_pic(PCXPIC *pic);<R>
  435. void pcx_invert_pic(PCXPIC *pic);
  436.  
  437. pcx_init_pic() dynamically allocates space for a PCXPIC structure, 
  438. and returns a pointer to it. <B>hres<D> & <B>vres<D> are the number 
  439. of dots horizontally and vertically; <B>nplanes<D> is the number of 
  440. planes in the picture. All arrays are dynamically allocated, and a 
  441. pointer to the result is returned. If an out of memory condition occurs, 
  442. any allocated arrays are de-allocated, and NULL is returned. pcx_free_pic() 
  443. is used to free up all the space allocated for a picture. pcx_invert_pic() 
  444. inverts all the bits in each row of the picture.
  445.  
  446. @PROTO = int pcx_read_pic(PCXPIC *pic,FILE *fp);<R>
  447. int pcx_getc(int *c,int *n,FILE *fp,int maxn);<R>
  448. int pcx_write_pic(PCXPIC *pic,FILE *fp);<R>
  449. int pcx_xputc(int c,FILE *fp);<R>
  450. int pcx_putc(int c,int n,FILE *fp);
  451.  
  452. These functions operate on a file which has been opened by one of 
  453. the STDIO buffered file open functions; <B>fp<D> is the file pointer 
  454. returned by the open call. <B>pic<D> is a pointer to a PCXPIC picture 
  455. structure. All these functions return OK or ERROR on failure.
  456.  
  457. pcx_read_pic() loads a picture from the file.  The pic structure can 
  458. either be statically allocated, or dynamically allocated using the 
  459. pcx_init_pic(0,0,0) call.  pcx_read_pic() automatically allocates 
  460. whatever arrays it needs to get the picture in.  pcx_write_pic() writes 
  461. the picture to the file.
  462.  
  463. pcx_getc() reads a character or pair of characters from the file.  The 
  464. character is placed in the integer pointed at by <B>c<D>, and a repeat 
  465. count of one or more is placed in the integer pointed at by <B>n<D>. 
  466. <B>maxn<D> is the maximum repeat count that the calling function wants 
  467. to receive. 
  468.  
  469. pcx_write_pic() calls pcx_xputc(), which counts the number of times 
  470. it receives a given byte value, then calls pcx_putc() with that number. 
  471. If pcx_xputc() is called with <B>c<D> == -1, the buffered byte value 
  472. and count are passed immediately (flushed) to pcx_putc(). pcx_putc() 
  473. writes the byte <B>c<D> to the file, using a repeat count of <B>n<D>. 
  474. <B>n<D> may have a value of up to 32767; pcx_putc() will recursively 
  475. call itself with <B>n<D><<=63 until the correct total has been written 
  476. to the file.
  477.  
  478. @PROTO = void pcx_showpic(PCXPIC *pic,int hoffs,int voffs,int load_palette_flg);
  479.  
  480. This function uses VGR_ROW to copy rows from the <B>pic<D> picture 
  481. to the video board driver module in use. <B>hoffs<D> is an offset 
  482. from the start of each row in <B>pic<D>. <B>voffs<D> is an offset 
  483. which is applied to the row number. These two offsets allow the screen 
  484. to be panned around a large picture. The <B>load_palette_flg<D>, when 
  485. set, allows pcx_showpic() to set the hardware palette registers from 
  486. the PCXPIC palette table. Consider the palette functions to be unreliable.
  487.  
  488. @MAJOR HEADING = The Test Routine
  489.  
  490. As I'm writing this, PCX.EXE is bug free and running.  It's essentially 
  491. a test routine which excercises the various modules. If executed without 
  492. command line parameters, it tries to figure out what kind of video 
  493. board is available. If a CGA/HERC/EGA board is found, it creates a 
  494. simple test picture (see figure 3,) displays it, then returns to DOS. 
  495.  
  496.  
  497. If it's invoked with a board name, CGA (640x200x2), EGA, HERC or CGA2 
  498. (320x200x4); it creates a picture for that board, and tries to display 
  499. it on that adapter. 
  500.  
  501. If it's invoked with a board name followed by a file name, the picture 
  502. is saved, using the specified file name, after it's been displayed.
  503.  
  504. PCXSHOW.EXE, the slide show program, is in need of some upgrading 
  505. <197> it was written before the latest improvements to the PCX/VGR 
  506. modules. It'll be ready before you see this, and will be included 
  507. with the other files.
  508.  
  509. @MAJOR HEADING = Bibliography
  510.  
  511. @BIBN = 1
  512.  
  513. @BIB = The IBM Personal Computer XT Technical Reference Manual, April 
  514. 1983 revision. Part Number 1502237.
  515.  
  516. @BIBN = 2
  517.  
  518. @BIB = The file EGA.ARC, which was found somewhere on Compu-Serve, 
  519. probably in one of the IBM forums.
  520.  
  521. @BIBN = 3
  522.  
  523. @BIB = ZSoft Technical Reference Manual.  ZSoft Corporation, 1950 
  524. Spectrum Circle, Suite A-495, Marietta, GA 30067.  Tel.  (404) 428-0008. 
  525. Many thanks to Shannon.
  526.  
  527. @BIBN = 4
  528.  
  529. @BIB = A Hercules Primer, by Larry Fogg, MicroCornucopia, Jan-Feb 
  530. 1988, page 26.
  531.  
  532. @BIBN = 5
  533.  
  534. @BIB = Tidbits, by Gary Entsminger, MicroCornucopia, Jan-Feb '88, 
  535. page 84.
  536.  
  537. @BIBN = 6
  538.  
  539. @BIB = Language Connections, by Gary Entsminger, Turbo Technix, Jan-Feb 
  540. '88, page 136. 
  541.  
  542. @BIBN = 7
  543.  
  544. @BIB = MicroEMACS by Dan Laurence & others. Public domain text editor, 
  545. with 'C sources. Available on BIX in LISTINGS/IBM.ARC.
  546.  
  547.